﻿using System;
using System.Collections.Generic;
using Microsoft.SharePoint;
using Kiiro.Common.Entities;
using Kiiro.Common.Utility;
using Kiiro.DataAccess;
using Kiiro.ExceptionManagement;
using Kiiro.Validation.Validators.Entities;

namespace Kiiro.Model
{
    public class WorkModel
    {
        public static Work GetById ( int workId, Guid siteCollectionId, string serverRelativeUrl )
        {
            Work workItem = null;
            List<Work> work = GetWorkByIds ( new List<int> ( ) { workId }, siteCollectionId, serverRelativeUrl );

            if ( work.Count > 0 )
                workItem = work [ 0 ];

            return workItem;
        }

        /// <summary>
        /// Gets a list of Work entities. If workIds is null or empty this method returns ALL Work.
        /// </summary>
        /// <param name="workIds">The list of work ids to get. If workIds is null or empty this method returns ALL Work.</param>
        /// <param name="siteCollectionId">The site collection id</param>
        /// <param name="serverRelativeUrl">The server relative url</param>
        /// <returns>If workIds is null or empty this method returns ALL Work.</returns>
        public static List<Work> GetWorkByIds ( List<int> workIds, Guid siteCollectionId, string serverRelativeUrl )
        {
            List<Work> work = WorkDA.Instance.GetWorkByIds ( workIds, siteCollectionId, serverRelativeUrl );

            if ( work.Count > 0 )
            {
                // TODO: GetTeamMembers won't return TeamMembers for deleted Users
                List<TeamMember> members = TeamModel.GetTeamMembers ( siteCollectionId, serverRelativeUrl );
                TeamMember member = null;

                // re-link CreatedBy and ModifiedBy properties
                foreach ( Work workItem in work )
                {
                    if ( workItem.CreatedBy != null && workItem.CreatedBy.Id != default ( int ) )
                    {
                        member = members.Find ( m => m.UserId == workItem.CreatedBy.Id );
                        if ( member != null )
                        {
                            workItem.CreatedBy = member.User;
                        }
                    }

                    if ( workItem.ModifiedBy != null && workItem.ModifiedBy.Id != default ( int ) )
                    {
                        member = members.Find ( m => m.UserId == workItem.CreatedBy.Id );
                        if ( member != null )
                        {
                            workItem.CreatedBy = member.User;
                        }
                    }
                }
            }

            return work;
        }

        public static List<Work> GetAllWork ( Guid siteCollectionId, string serverRelativeUrl )
        {
            return GetWorkByIds ( null, siteCollectionId, serverRelativeUrl );
        }

        public static List<Work> GetMyWork ( Guid siteCollectionId, string serverRelativeUrl, User currentUser )
        {
            return WorkDA.Instance.GetMyWork ( siteCollectionId, serverRelativeUrl, currentUser );
        }

        public static List<Work> GetAllTasks ( Guid siteCollectionId, string serverRelativeUrl)
        {            
            return WorkDA.Instance.GetAllTasks ( siteCollectionId, serverRelativeUrl );
        }
        
        public static Work Save ( Work work, Guid siteCollectionId, string serverRelativeUrl )
        {
            return Save ( work, siteCollectionId, serverRelativeUrl, false, false );
        }

        public static Work Save(Work work, Guid siteCollectionId, string serverRelativeUrl, bool fromAjax)
        {
            return Save(work, siteCollectionId, serverRelativeUrl, fromAjax, false);
        }

        public static Work Save ( Work work, Guid siteCollectionId, string serverRelativeUrl, bool fromAjax, bool fromTimerJob )
        {
            if (work.EditType == EditType.Deleted)
            {  
                //Store the current User who is deleting Work
                User currentUser = work.ModifiedBy;
                // Populate the work item so it can be used to adjust the project stats
                work = GetById(work.Id, siteCollectionId, serverRelativeUrl);
                work.EditType = EditType.Deleted;
                //Reassign the current User who is deleting Work
                work.ModifiedBy = currentUser;
            }

            Midori midori = new Midori ( );
            midori.Work.Add ( work );
            midori = Save ( midori, siteCollectionId, serverRelativeUrl, fromAjax, false, fromTimerJob );

            if ( midori.Work.Count > 0 )
                work = midori.Work[0];

            return work;
        }

        public static Midori Save ( Midori midori, Guid siteCollectionId, string serverRelativeUrl )
        {
            return Save ( midori, siteCollectionId, serverRelativeUrl, false, true, false );
        }

        public static Midori Save ( Midori midori, Guid siteCollectionId, string serverRelativeUrl, bool fromAjax, bool fromPlugin, bool fromTimerJob )
        {
            try
            {
                foreach ( Work work in midori.Work )
                {
                    if ( work != null && work.EditType != EditType.Unchanged )
                    {
                        if ( !fromTimerJob )
                            PermissionsModel.GetGlobalPermissionBitsForCurrentUser ( work, work.ModifiedBy, siteCollectionId, serverRelativeUrl, false );

                        if ( fromTimerJob || (work.PermissionBitsWork != null && work.PermissionBitsWork.Count > 0 &&
                            ( work.PermissionBitsWork[0] || work.PermissionBitsWork[2] || work.PermissionBitsWork[3] )) )
                        {
                            // TODO: Add validation methods to partially validate the work item when fromAjax or fromPlugin
                            if ( !fromAjax && !fromPlugin && !fromTimerJob )
                                new WorkValidator ( ).Validate ( work );

                            if ( fromAjax || work.EditType == EditType.Deleted || work.IsValid ( ) )
                            {
                                Work beforeWork = null;
                                bool created = work.EditType == EditType.Created;
                                if (fromAjax || work.EditType == EditType.Updated)
                                {
                                    beforeWork = GetById(work.Id, siteCollectionId, serverRelativeUrl);
                                    work.BeforeAssignedWork = beforeWork.AssignedWork;
                                    work.BeforeStart = beforeWork.StartDate;
                                    work.BeforeEnd = beforeWork.EndDate;
                                    work.BeforePercentComplete = beforeWork.PercentageComplete;
                                    work.BeforeStatus = work.Status;
                                }

                                #region Perform Calculations
                                // update task status
                                if ( work.WorkItemType == WorkType.Task )
                                {
                                    work.Status = GetTaskStatus ( work );
                                }
                                #endregion // Perform Calculations

                                bool sendEmail = (work.EditType == EditType.Created || work.EditType == EditType.Updated);// && !fromPlugin;
                                
                                List<Attachment> attachments = work.AttachmentList;



                                WorkDA.Instance.Save ( work, siteCollectionId, serverRelativeUrl );

                                work.AttachmentList = attachments;
                                if ( work.EditType != EditType.Deleted )
                                    AttachmentModel.SaveAttachments ( work, siteCollectionId, serverRelativeUrl );

                                if (sendEmail)
                                    SendEmail(beforeWork, work, siteCollectionId, serverRelativeUrl, created, work.ModifiedBy);
                                
                                // update project statistics
                                if (!fromTimerJob && !fromPlugin)
                                    ProjectsModel.UpdateProjectStatistics ( midori, siteCollectionId, serverRelativeUrl );
                            }
                        }
                        else
                            throw new KiiroUnauthorizedAccessException ( "Updating Work Failed: Access Denied." );
                    }
                }
                // update project statistics
                if (fromPlugin)
                    ProjectsModel.UpdateProjectStatistics(midori, siteCollectionId, serverRelativeUrl);

            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return midori;
        }



        private static void SendEmail(Work beforeWork, Work work, Guid siteCollectionId, string serverRelativeUrl, bool created, User currentUser)
        {
            if (work.AssignedToList.Count > 0)
            {
                List<User> users = UserModel.GetUsersByIds(work.AssignedToList, siteCollectionId, serverRelativeUrl);

                foreach (User user in users)
                {
                    if (created || (beforeWork.AssignedToList != null && !beforeWork.AssignedToList.Contains(user.Id)))
                    {
                        if (user.ReceiveEmailNotification)
                        {
                            string workDisplayUrl = default(string);
                            string[] args = new string[] { default(string) };
                            using (SPWeb web = SPHelpers.GetWeb(siteCollectionId, serverRelativeUrl))
                            {
                                if (work.WorkItemType == WorkType.Issue)
                                    workDisplayUrl = web.Url + Constants.ProjectFileUrls.IssueDisplay + "?Id=" + work.Id;
                                else
                                    workDisplayUrl = web.Url + Constants.ProjectFileUrls.TaskDisplay + "?Id=" + work.Id;

                                workDisplayUrl = EmailModel.Instance.FixUrlForUserZone(workDisplayUrl, user);
                                string webUrl = EmailModel.Instance.FixUrlForUserZone(web.Url, user);

                                args = new string[] { work.WorkItemType.ToString(), 
                                                            work.Title,
                                                            workDisplayUrl,
                                                            web.Title,
                                                            webUrl};
                            }

                            EmailModel.Instance.SendNotificationEmail(EmailModel.EmailType.WorkAssignment, user.Email, args, currentUser);
                        }
                    }
                }
            }
        }

        private static StatusType GetTaskStatus ( Work work )
        {
            StatusType status = StatusType.NotStarted;

            if ( work.PercentageComplete <= 0 )
                status = StatusType.NotStarted;
            else if ( work.PercentageComplete >= 100 )
                status = StatusType.Completed;
            else
                status = StatusType.InProgress;

            return status;
        }

        public static List<Work> GetUserWorkCrossProjects(Guid siteCollectionId, string serverRelativeUrl, User currentUser)
        {
            List<Work> currentUserWork = new List<Work>();
            currentUserWork = WorkDA.Instance.GetCurrentUserWorkOnProjects(siteCollectionId, serverRelativeUrl, currentUser);
            return currentUserWork;
        }
    }
}

/*************************************************************************
 * 
 * $Log: /Internal Projects/Kiiro/Kiiro.Model/WorkModel.cs $
 * 
 * 22    2/08/10 5:04p Camerons
 * 
 * 21    1/25/10 1:17p Camerons
 * 
 * 20    1/12/10 12:03p Camerons
 * 
 * 19    26/11/09 10:35a Camerons
 * 
 * 18    17/11/09 6:46p Camerons
 * 
 * 17    10/02/09 10:46a Stefanf
 * 
 * 16    22/09/09 6:03p Camerons
 * Code changes to support creating user on demand - version 1.1.x.x
 * 
 * 15    10/09/09 9:22a Shafia
 * 
 * 14    17/08/09 10:29a Camerons
 * Added check-in comments section
 * 
 ************************************************************************/